package com.example.zxw.net

import ApiException
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.alibaba.android.arouter.launcher.ARouter
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.net.ssl.SSLHandshakeException

typealias Block<T> = suspend (CoroutineScope) -> T
typealias Error = suspend (ApiException) -> Unit
typealias Cancel = suspend (Exception) -> Unit
typealias NetErr = suspend (Exception) -> Unit

open class BaseViewModel : ViewModel() {



    /**
     * 创建并执行协程任务
     * @param block 协程任务执行
     * @param error 执行过程中的异常执行
     * @param cancel 协程任务取消时执行
     */
    protected fun launch(
        block: Block<Unit>,
        apiError: Error? = null,
        cancel: Cancel? = null,
        netErr: NetErr? = null
    ): Job {


        return viewModelScope.launch {
            try {
                block.invoke(this)
            } catch (e: Exception) {
                when (e) {
                    is CancellationException -> {
                        cancel?.invoke(e)
                    }

                    is ApiException -> {
                        apiError?.invoke(e)
                    }

                    else -> {
                        onError(e, netErr)
                    }
                }
            }
        }
    }

    /**
     *统一异常处理
     * @param e 异常
     */
    private suspend fun onError(e: Exception, error: NetErr?) {
        when (e) {
            // 网络请求失败
            is ConnectException,
            is SocketTimeoutException,
            is UnknownHostException,
            is HttpException,
            is SocketException,
            is SSLHandshakeException -> {
                error?.invoke(e)
            }

            else -> {
                error?.invoke(e)
            }
        }
    }

    /**
     *执行协程异步任务
     */
    protected fun <T> async(block: Block<T>): Deferred<T> {
        return viewModelScope.async { block.invoke(this) }
    }

    /**
     * 取消执行
     */
    protected fun cancelJob(job: Job?) {
        if (job != null && job.isActive && !job.isCompleted && !job.isCancelled) {
            job.cancel()
        }
    }
}